package cz.movie.subRenamer.worker.impl;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cz.movie.subRenamer.model.FileRepresentation;
import cz.movie.subRenamer.model.SearchingRule;
import cz.movie.subRenamer.util.FileNameUtil;
import cz.movie.subRenamer.worker.CoreWorker;

public class CoreWorkerImpl implements CoreWorker {

	static final Logger logger = LoggerFactory.getLogger(CoreWorkerImpl.class);

	private List<SearchingRule> rules;
	private Pattern number = Pattern.compile("\\d+");
	public String output;

	public CoreWorkerImpl(List<SearchingRule> rules) {
		this(rules, null);
	}

	public CoreWorkerImpl(List<SearchingRule> rules, String output) {
		this.rules = rules;
		this.output = output;
	}

	/**
	 * convertFileToRepresentation *********************************************************
	 */
	public List<FileRepresentation> convertFileToRepresentation(List<File> files) {
		LinkedList<FileRepresentation> filesRepres = new LinkedList<FileRepresentation>();
		for (File file : files) {
			FileRepresentation fileRepresentation = new FileRepresentation();
			String name = file.getName();
			int startExtension = name.lastIndexOf(".");
			fileRepresentation.setExtension(name.substring(startExtension + 1));
			if (fileRepresentation.hasPlayableExtension() || fileRepresentation.hasSubtitleExtension()) {
				tryRulesOnTheFile(filesRepres, file, fileRepresentation, FileNameUtil.getNameWithnoutExtension(name));
			}
		}
		return filesRepres;
	}

	private void tryRulesOnTheFile(LinkedList<FileRepresentation> filesRepres, File file, FileRepresentation fileRepresentation, String name) {
		for (SearchingRule rule : rules) {
			Matcher matcher = rule.getPattern().matcher(name);
			if (matcher.find()) {
				String substring = matcher.group();
				Matcher numberMatcher = number.matcher(substring);
				int firstNumber;
				int secondNumber;
				if (numberMatcher.find()) {
					firstNumber = Integer.parseInt(numberMatcher.group());
				} else {
					break;
				}

				if (numberMatcher.find()) {
					secondNumber = Integer.parseInt(numberMatcher.group());
					fileRepresentation.setSeason(rule.isReverseOrder() ? secondNumber : firstNumber);
					fileRepresentation.setEpisodeNumber(rule.isReverseOrder() ? firstNumber : secondNumber);
					fileRepresentation.setName(cleanName(name.substring(matcher.end())));
					if (numberMatcher.find()) {
						int thirdNumber = Integer.parseInt(numberMatcher.group());
						fileRepresentation.setEpisodeSpecial(secondNumber + "-" + thirdNumber);
					}
				} else {
					if (firstNumber > 99) {
						fileRepresentation.setSeason(firstNumber / 100);
						fileRepresentation.setEpisodeNumber(firstNumber % 100);
						fileRepresentation.setName(cleanName(name.substring(matcher.end())));
					} else {
						break;
					}
				}
				fileRepresentation.setFile(file);
				filesRepres.add(fileRepresentation);
				logger.info("founded: " + fileRepresentation.getFile().getAbsolutePath());
				break;
			}
		}
	}

	private String cleanName(String substring) {
		String s = cleanEasy(substring);
		if (s.startsWith("]") || s.startsWith(")") || s.startsWith("}")) {
			s = s.substring(1).trim();
		}
		return s;
	}

	private String cleanEasy(String substring) {
		String s = substring.replace("-", " ").replace(".", " ").replace("_", " ").trim();
		return s;
	}

	/**
	 * assingSubtitlesToMovies *********************************************************
	 */
	public List<FileRepresentation> assingSubtitlesToMovies(List<FileRepresentation> list) {
		List<FileRepresentation> movies = getOnlyMovies(list);
		HashMap<String, FileRepresentation> moviesMap = new HashMap<String, FileRepresentation>();
		for (FileRepresentation mov : movies) {
			moviesMap.put(mov.getStringRepresentation(), mov);
		}
		List<FileRepresentation> subtitles = getOnlySubtitles(list);
		for (FileRepresentation sub : subtitles) {
			FileRepresentation movie = moviesMap.get(sub.getStringRepresentation());
			if (movie != null) {
				movie.getSubtitles().add(sub);
			} else {
				logger.warn("no movie for subtitle: {}", sub.toString());
			}
		}
		return movies;
	}

	private List<FileRepresentation> getOnlySubtitles(List<FileRepresentation> list) {
		LinkedList<FileRepresentation> subtitles = new LinkedList<FileRepresentation>();
		for (FileRepresentation fileRepresentation : list) {
			if (fileRepresentation.hasSubtitleExtension()) {
				subtitles.add(fileRepresentation);
			}
		}
		return subtitles;
	}

	private List<FileRepresentation> getOnlyMovies(List<FileRepresentation> list) {
		LinkedList<FileRepresentation> movies = new LinkedList<FileRepresentation>();
		for (FileRepresentation fileRepresentation : list) {
			if (fileRepresentation.hasPlayableExtension()) {
				movies.add(fileRepresentation);
			}
		}
		return movies;
	}

	/**
	 * renameAndMoveSubtitles *********************************************************
	 * 
	 */

	public void renameAndMoveSubtitles(List<FileRepresentation> movies, String defaultLanguage) {
		for (FileRepresentation movie : movies) {
			File parentFile = movie.getFile().getParentFile();
			String name = FileNameUtil.getNameWithnoutExtension(movie.getFile().getName());
			List<FileRepresentation> subtitles = movie.getSubtitles();
			for (FileRepresentation subtitle : subtitles) {
				File subFile = subtitle.getFile();
				File newSubLocation = getUniqueSubtitleFile(parentFile, name, subtitle, defaultLanguage, subFile);
				if (newSubLocation == null) {
					subFile.delete();
					continue;
				}
				logger.info("renaming subtitles {} to {}", subFile.getAbsolutePath(), newSubLocation);
				subFile.renameTo(newSubLocation);
			}
		}
	}

	private File getUniqueSubtitleFile(File parentFile, String name, FileRepresentation subtitle, String defaultLanguage, File sourceFile) {
		String lang = subtitle.getLanguage() == null ? defaultLanguage : subtitle.getLanguage();
		File newSubLocation = new File(parentFile, name + "." + (lang.isEmpty() ? lang : lang + ".") + subtitle.getExtension());
		int i = 1;
		while (newSubLocation.exists()) {
			i++;
			try {
				if (FileUtils.checksumCRC32(newSubLocation) == FileUtils.checksumCRC32(sourceFile)) {
					if (sourceFile.getAbsolutePath().equals(newSubLocation.getAbsolutePath())) {
						return sourceFile;
					}
					return null;
				}
			} catch (IOException e) {
				System.err.println("cannot compute checksum");
				e.printStackTrace();
			}
			newSubLocation = new File(parentFile, name + "." + lang + i + "." + subtitle.getExtension());
		}
		return newSubLocation;
	}

	/**
	 * renameMovies *********************************************************
	 * 
	 */

	public void renameMovies(List<FileRepresentation> list, String removeFromName) {
		if (output == null || output.isEmpty()) {
			return;
		}
		for (FileRepresentation movie : list) {
			File file = movie.getFile();
			String createNameForPattern = movie.createNameForPattern(output);
			for (String exclude : removeFromName.split(";")) {
				createNameForPattern = createNameForPattern.replace(cleanEasy(exclude), "");
			}
			createNameForPattern = createNameForPattern.replaceAll("\\s+", " ");
			File newFile = new File(file.getParent(), createNameForPattern);
			if (file.renameTo(newFile)) {
				logger.info("renaming movie file: " + file.getAbsolutePath() + " to file: " + newFile.getAbsolutePath());
				movie.setFile(newFile);
			} else {
				logger.warn("cant rename file: " + file.getAbsolutePath() + " to file: " + newFile.getAbsolutePath());
			}
		}
	}
}
